﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 遗传算法测试
{
    public partial class MainForm : Form
    {
        ShowForm sourceForm = new ShowForm();
        ShowForm targetForm = new ShowForm();
        ShowForm[] ancestorForm = new ShowForm[count];


        int[] source = new int[] {  0,0,0,0,0,0,
                                    0,1,0,0,1,0,
                                    0,0,0,0,0,0,
                                    1,0,0,0,0,1,
                                    0,1,1,1,1,0,
                                    0,0,0,0,0,0
        };

        static int count = 5;
        static int length = 36;

        /// <summary>
        /// 染色体
        /// </summary>
        int[][] chromosome = new int[count][];

        /// <summary>
        /// 目前所有染色体
        /// </summary>
        List<int[]> nowAncestor = new List<int[]>();

        public MainForm()
        {
            InitializeComponent();

            ClientSize = new Size(800, 600);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            Controls.Add(sourceForm);
            Controls.Add(targetForm);

            sourceForm.Location = new Point(0, 0);
            sourceForm.Text = "原始图像";
            sourceForm.Show();
            sourceForm.ShowNumber(source);
            targetForm.Location = new Point(0, 360);
            targetForm.Text = "当前最优";
            targetForm.Show();

            for (int i = 0; i < count; i++)
            {
                ancestorForm[i] = new ShowForm();
                ancestorForm[i].Location = new Point(330 + 330 * (i % 3), (i / 3) * 360);
                Controls.Add(ancestorForm[i]);
                ancestorForm[i].Show();
                ancestorForm[i].Text = $"第【{i + 1}】个祖先";
            }

            InitAncestors();
        }

        /// <summary>
        /// 初始化染色体
        /// </summary>
        public void InitAncestors()
        {
            for (int i = 0; i < count; i++)
            {
                chromosome[i] = new int[length];
                for (int j = 0; j < length; j++)
                {
                    Random random = new Random((int)DateTime.Now.Ticks);
                    int num = random.Next(100);
                    chromosome[i][j] = num % 2;
                }

                ancestorForm[i].ShowNumber(chromosome[i]);
            }
        }

        /// <summary>
        /// 随机交换两个祖先的5个连续位置，形成新的祖先
        /// </summary>
        /// <param name="one"></param>
        /// <param name="two"></param>
        public void ExchangeTwoAncestors(int[] one, int[] two)
        {
            Random random = new Random((int)DateTime.Now.Ticks);
            int index = random.Next(36 - 5);

            int[] three = (int[])one.Clone();
            int[] four = (int[])two.Clone();

            for (int i = index; i < index + 5; i++)
            {
                three[i] = two[i];
                four[i] = one[i];
            }

            nowAncestor.Add(three);
            nowAncestor.Add(four);
        }

        /// <summary>
        /// 随机选择一个位置进行变异
        /// </summary>
        /// <param name="nums"></param>
        public void ChangeSelf(int[] nums)
        {
            int[] next = (int[])nums.Clone();
            Random random = new Random((int)DateTime.Now.Ticks);
            int index = random.Next(next.Length);
            next[index] = 1 - next[index];
            nowAncestor.Add(next);
        }

        /// <summary>
        /// 随机选择一个祖先进行变异
        /// </summary>
        public void RandomChangeSelf()
        {
            Random random = new Random((int)DateTime.Now.Ticks);
            int select = random.Next(count);
            ChangeSelf(chromosome[select]);
        }

        /// <summary>
        /// 随机选择两对祖先进行交配
        /// </summary>
        public void RandomExchangTwoPairAncestors()
        {
            bool[] flag = new bool[count];
            List<int> index = new List<int>();

            for (int i = 0; i < 4; i++)
            {
                Random random = new Random((int)DateTime.Now.Ticks);
                int select = random.Next(count);
                while (flag[select])
                {
                    select++;
                    if (select >= count)
                    {
                        select = 0;
                    }
                }
                flag[select] = true;
                index.Add(select);
            }

            ExchangeTwoAncestors(chromosome[index[0]], chromosome[index[1]]);
            ExchangeTwoAncestors(chromosome[index[2]], chromosome[index[3]]);
        }

        public int Cha(int[] nums)
        {
            int r = 0;
            for(int i = 0; i < length; i++)
            {
                r +=(int) Math.Pow(nums[i] - source[i], 2);
            }
            return r;
        }

        /// <summary>
        /// 选择适合的祖先
        /// </summary>
        public void SelectRightChromosome()
        {
            List<int[]> chrs = new List<int[]>();
            chrs.AddRange(chromosome);
            chrs.AddRange(nowAncestor);
            List<int> cha = new List<int>();
            for(int i = 0; i < chrs.Count; i++)
            {
                cha.Add(Cha(chrs[i]));
            }

            for(int i=0;i< cha.Count - 1; i++)
            {
                int k = i;
                for(int j = i + 1; j < cha.Count; j++)
                {
                    if (cha[j] < cha[i])
                    {
                        k = j;
                    }
                }
                if (k != i)
                {
                    int t = cha[i];
                    cha[i] = cha[k];
                    cha[k] = t;

                    int[] temp = chrs[i];
                    chrs[i] = chrs[k];
                    chrs[k] = temp;
                }
            }

            nowAncestor = new List<int[]>();
            chromosome = chrs.Take(count).ToArray();
            fitness = cha[0];
        }

        int no = 1;
        int fitness = int.MaxValue;

        private void timer_Tick(object sender, EventArgs e)
        {
            //两对祖先交配
            RandomExchangTwoPairAncestors();
            //一个祖先变异
            RandomChangeSelf();

            //筛选适配度高的结果
            SelectRightChromosome();

            //重新显示
            for (int i = 0; i < count; i++)
            {
                ancestorForm[i].ShowNumber(chromosome[i]);
            }
            targetForm.ShowNumber(chromosome[0]);
            Debug.WriteLine($"第{no++}代遗传，适合度{-fitness}");

            if (-fitness == 0)
            {
                Debug.WriteLine("遗传算法结束，已找到最优解！");
                timer.Enabled = false;
                MessageBox.Show("算法结束！");
            }
        }
    }
}
